package com.example;

import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTHeader;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.AlgorithmUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;

// 使用 hutool 生成 jwt token
@SpringBootTest
public class JwtTest {

    // 使用默认 HS265(HmacSHA256) 算法生成 jwt token
    @Test
    public void test() {
        // 密钥
        byte[] key = "1234567890".getBytes();

        String token = JWT.create()
                // 设置签发时间
                .setIssuedAt(DateUtil.date())
                // 设置过期时间，1天有效期，使用 DateUtil.offsetDay
                // .setExpiresAt(DateUtil.offsetDay(DateUtil.date(), 1))
                // 1分钟有效，使用 DateUtil.offsetMinute
                .setExpiresAt(DateUtil.offsetMinute(DateUtil.date(), 1))
                .setPayload("sub", "1234567890")
                .setPayload("name", "looly")
                .setPayload("admin", true)
                .setKey(key)
                .sign();
        System.out.println(token);

        // (签发时间)---------(生效时间)---------(当前时间)---------(失效时间)
        // 签发时间和生效时间一般没有前后要求，都早于当前时间即可。
        // 由于定义了签发时间、过期时间，因此会检查签发时间是否早于当前时间，过期时间是否晚于当前时间。
        // 如果 token 过期则会抛出异常 cn.hutool.core.exceptions.ValidateException: 'exp':[2025-01-05 23:46:30] is before now:[2025-01-05 23:50:28]
        JWTValidator.of(token).validateDate(DateUtil.date());

        // jwt token 创建方式二，使用 JWTUtil
        // 头部，设置token说明信息，例如： 加密算法、签发人、签发时间、过期时间等
        HashMap<String, Object> headers = new HashMap<>();
        headers.put("alg", "HS256");
        // 数据载体
        HashMap<String, Object> payload = new HashMap<>();
        payload.put("sub", "1234567890");
        String token1 = JWTUtil.createToken(headers, payload, JWTSignerUtil.createSigner("HS256", key));

    }

    // 使用其他算法生成 jwt token
    @Test
    public void test2() {
        // 密钥
        byte[] key = "1234567890".getBytes();

        // SHA256withRSA
        String id = "rs256";
        JWTSigner signer = JWTSignerUtil.createSigner(id,
                // 随机生成密钥对，此处用户可自行读取`KeyPair`、公钥或私钥生成`JWTSigner`
                KeyUtil.generateKeyPair(AlgorithmUtil.getAlgorithm(id)));

        String token = JWT.create()
                .setPayload("sub", "1234567890")
                .setPayload("name", "looly")
                .setPayload("admin", true)
                .setSigner(signer)
                .sign();
    }

    // 解析 jwt token
    @Test
    public void test3() {
        String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
                "eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9." +
                "536690902d931d857d2f47d337ec81048ee09a8e71866bcc8404edbbcbf4cc40";

        JWT jwt = JWT.of(rightToken);

        // JWT
        Object header = jwt.getHeader(JWTHeader.TYPE);
        // 打印
        System.out.println(header);
        // HS256
        Object header1 = jwt.getHeader(JWTHeader.ALGORITHM);
        System.out.println(header1);

        // 1234567890
        jwt.getPayload("sub");
        // looly
        jwt.getPayload("name");
        // true
        jwt.getPayload("admin");
    }

    // 验证 jwt token
    @Test
    public void test4() {
        String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." +
                "eyJpYXQiOjE3MzYwOTE5MzAsImV4cCI6MTczNjA5MTk5MCwic3ViIjoiMTIzNDU2Nzg5MCIsIm5hbWUiOiJsb29seSIsImFkbWluIjp0cnVlfQ." +
                "VJwtRdMuGeeeqJm_Mut2qPPyroLs7tvQjtuEZb4NFmI";

        // 密钥
        byte[] key = "1234567890".getBytes();

        // 默认验证HS265的算法
        // 由于JWT.verify，只能验证JWT Token的签名是否有效，其他payload字段验证都可以使用JWTValidator完成。
        boolean verify = JWT.of(rightToken).setKey(key).verify();
        System.out.println(verify);

        // 验证时间
        // (签发时间)---------(生效时间)---------(当前时间)---------(失效时间)
        // 签发时间和生效时间一般没有前后要求，都早于当前时间即可。
        // 由于定义了签发时间、过期时间，因此会检查签发时间是否早于当前时间，过期时间是否晚于当前时间。
        // 如果 token 过期则会抛出异常 cn.hutool.core.exceptions.ValidateException: 'exp':[2025-01-05 23:46:30] is before now:[2025-01-05 23:50:28]
        JWTValidator.of(rightToken).validateDate(DateUtil.date());

        // 使用指定算法验证
        boolean verify2 = JWT.of(rightToken).setSigner(JWTSignerUtil.hs256(key)).verify();
    }
}
